package com.lagou.utils;

import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;
import com.lagou.pojo.ResultMap;
import com.lagou.pojo.ResultMapping;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @Authther: mrwu
 * @date:2021/3/9-03
 * @Description:com.lagou.utils
 */
public class MapResultSetHandler implements ResultSetHandler{
    private  List<Object> results=new ArrayList<>();
    //用来对比最外层是否为同一对象 对应为sql查询出来的每一行（这种方法sql必须必须按照主键排序）
    private String lastKey ="";
    //将最外层的数据按照最外层查询出的值的字符串组合当作key value 为返回的objec
    //在遍历没一行sql 时 从字典中拿出对象 进行赋值
    private HashMap<String,Object> preResultsMap = new HashMap<String, Object>();
    //当前数组属性的属性名称
    private String currentofkey ="";
    //当前javatype变量的属性名称
    private String currentjkey="";
    //用来存放需要封装数组对象时的对象值
    private List<Object> ofresult=new ArrayList<>();
    @Override
    public <E> List<E> handerResultSet(ResultSet resultSet, MappedStatement stmt, Configuration config) throws Exception {

        while (resultSet.next()) {
            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取要返回对象的class 全限定名称
            String resultType = stmt.getResultType();
            //怎么获取namesapce 在mapstament 中增加namespace属性
            String resultMapKey = stmt.getNamespace() + resultType;
            ResultMap resultMap = config.getMappedResultMap().get(resultMapKey);
//            System.out.println("获取到resultmap"+resultMap);
            if (resultMap != null) {
                //复杂映射关系
                //获取返回的类对象的真正名称
                resultType = resultMap.getType();
                Object o = Class.forName(resultType).newInstance();
                String javaType = resultMap.getJavaType() != null ? resultMap.getJavaType() : "";
                String ofType = resultMap.getOfType() != null ? resultMap.getOfType() : "";
                Object ofobj = ofType == "" ? null : Class.forName(ofType).newInstance();

                Object jobj = javaType == "" ? null : Class.forName(javaType).newInstance();
                String tempKey = "";
                for (int i = 0; i < metaData.getColumnCount(); i++) {
                    // 字段名 优先使用别名
                    String columnName = metaData.getColumnLabel(i + 1);
                    // 字段的值
                    Object value = resultSet.getObject(columnName);
                    //根据columnname 获取property （属性名称）
//                    System.out.println("当前解析到的列是"+columnName);
                    ResultMapping resultMapping = resultMap.getResultMappingMap().get(columnName);
                    //解决未定义的列造成的空的问题
                    if (resultMapping == null) {
                        continue;
                    }
                    //获取外层属性
                    String property = resultMapping.getProperty();
                    //获取内层节点的外层封装属性值
                    String parentProperty = resultMapping.getParentProperty();
                    //如果oftype和Javatype 都为null 则说明是最外层值
                    if (resultMapping.getOfType() == null & resultMapping.getJavaType() == null) {
                        tempKey += value;
                        //利用反射进行赋值
                        Field field = o.getClass().getDeclaredField(property);
                        field.setAccessible(true);
                        field.set(o, value);
                    } else if (javaType.equals(resultMapping.getJavaType())) {
                        currentjkey=parentProperty;
                        //说明当前对象包含另外一个对象
                        Field field = jobj.getClass().getDeclaredField(property);
                        field.setAccessible(true);
                        field.set(jobj, value);

                    }
                    if (ofType.equals(resultMapping.getOfType())) {
                        //说明当前对象包含另外一个对象的集合
                        Field field = ofobj.getClass().getDeclaredField(property);
                        field.setAccessible(true);
                        field.set(ofobj, value);
                        currentofkey = parentProperty;
                    }
                }
                //组装外层obj
                //封装Javatype成员变量
                if (currentjkey.length()>0) {
                    Field field = o.getClass().getDeclaredField(currentjkey);
                    field.setAccessible(true);
                    field.set(o, jobj);
                    results.add(o);
                    continue;
                }
                //组装数组成员变量
                Field field = o.getClass().getDeclaredField(currentofkey);
                field.setAccessible(true);
                //从预存结果字典中查询 如果值不为空则取出
                Object hasobj = preResultsMap.get(tempKey);
                if (hasobj != null) {
                    Field hasobjOfField = hasobj.getClass().getDeclaredField(currentofkey);
                    hasobjOfField.setAccessible(true);
                    //说明是同一个外层对象 将ofobj对象加入到o的ofobj数组中
                    List hasobjoflist = (List) hasobjOfField.get(hasobj);
                    hasobjoflist.add(ofobj);

                    field.set(o, hasobjoflist);
                    preResultsMap.put(tempKey, o);
                } else {
                    //向最后结果中添加对象
                    ofresult = new ArrayList<>();
                    ofresult.add(ofobj);
                    field.set(o, ofresult);
                    preResultsMap.put(tempKey, o);
                    results.add(o);

                }
            }
        }
        return (List<E>) results;
    }
}
